#include <iostream>

#include "Socket.hpp"
#include "log.hpp"
const int fd_num_max=sizeof(fd_set)*8;  //4096
int defaultfd = -1;
uint16_t defaultport=8080;
class select_server
{
public:

    select_server(uint16_t port=defaultport)
    :_port(port)
    
    {
        //置空
        for (int i = 0; i < fd_num_max; i++)
        {
            _fd_array[i] = defaultfd;
            // std::cout << "fd_array[" << i << "]" << " : " << fd_array[i] << std::endl;
        }
    }

    //服务器初始化
    void Init()
    {
        //1.创建套接字
        _socket.Socket();
        //2.绑定
        _socket.Bind(_port);
        //3.监听
        _socket.Listen();
    }


    //链接，保存fd   
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport = 0;
        //链接到队列中

        //sockfd一直在增加，多个链接
        int _sockfd=_socket.Accept(clientip,&clientport);
        if(_sockfd<0) return;
        lg(Info, " Accept success: ");
        
        //将这个_sockfd保存，交给select
        int pos=1;  //pos=0的位置留给套接字listensockfd   
        for (; pos < fd_num_max; pos++) // 第二个循环
        {
            if (_fd_array[pos] != defaultfd)
                continue;
            else
                break;
        }
        if (pos == fd_num_max)
        {
            lg(Warning, "server is full, close %d now!", _sockfd);
            close(_sockfd);
        }
        else
        {
            _fd_array[pos]=_sockfd;
            PrintFd();
        }
    }


    //读取函数    
    void Rever(int fd,int pos)
    {
        //读取
        char buffer[1024];
        ssize_t n=read(fd,buffer,sizeof(buffer) - 1);
        if(n>0)
        {
            buffer[n] = 0;
            cout << "get a messge: " << buffer << endl;
        }
        //没有数据
        else if(n==0)
        {
            lg(Info, "client quit, me too, close fd is : %d", fd);
            close(fd);
            _fd_array[pos] = defaultfd; // 这里本质是从select中移除
        }
        else
        {
            lg(Warning, "recv error: fd is : %d", fd);
            close(fd);
            _fd_array[pos] = defaultfd; // 这里本质是从select中移除
        }

    }


    void Start()
    {
        //获取套接字fd listensockfd
        int listensockfd=_socket.get_sockfd();
        _fd_array[0] = listensockfd;
        //将保存的sockfd交给select来等待
        while(1)
        {
            //设置位图
            fd_set rfd;
            FD_ZERO(&rfd);
            int maxfd=_fd_array[0];
            for(int i=0;i<fd_num_max;i++)
            {
                if (_fd_array[i] == defaultfd)
                    continue;
                FD_SET(_fd_array[i],&rfd);

                //select参数有最大监听文件描述符参数  maxfd
               
                if(maxfd<_fd_array[i])
                {
                    maxfd = _fd_array[i];
                    lg(Info, "max fd update, max fd is: %d", maxfd);
                }
            }
            //最后一个参数是超时时间
            //nullptr：一直阻塞
            //0：不等待，直接返回
            //设置时间：
            //返回值：
            struct timeval timeout ={1,0};
            int n=select(maxfd+1,&rfd,nullptr,nullptr,&timeout);
            
            //超时处理
            if(n==0)
            {
                std::cout << "time out, timeout: " << timeout.tv_sec << "." << timeout.tv_usec << std::endl;
            }
            //错误处理
            else if(n==-1)
            {
                std::cerr<<  "select error" <<std::endl;
            }
            //有事件等待完成  通过rfd来判断哪个文件描述符完成了
            else
            {
                std::cout << "get a new link!!!!!" <<std:: endl;
                
                //通过派发函数来实现对于任务的执行
                Dispatch(rfd);
            }
        }
            
    }

    void Dispatch(fd_set&rfd)
    {
        //判断
        for(int i=0;i<fd_num_max;i++)
        {
            //_fd_array有些是空的
            if(_fd_array[i]==-1) continue;
            
            if(FD_ISSET(_fd_array[i],&rfd))
            {
                //监听   链接等到了 ，完成链接
                if(_fd_array[i]==_socket.get_sockfd())
                {
                    Accepter();
                }
                // Accept 套接字通信的sockfd 
                else
                {
                    //接收消息
                    Rever(_fd_array[i],i);
                }
            }
        }
    }

    
    void PrintFd()
    {
        cout << "online fd list: ";
        for (int i = 0; i < fd_num_max; i++)
        {
            if (_fd_array[i] == defaultfd)
                continue;
            std::cout << _fd_array[i] << " ";
        }
        cout << endl;
    }


    ~select_server()
    {
        _socket.Close();
    }


private:
    Sock _socket;

    //select 
    int _fd_array[fd_num_max];  //文件描述符
    uint16_t _port;
    
};

